package cn.xiaoliu.hrm.controller;

import cn.xiaoliu.hrm.config.HighlightResultMapper;
import cn.xiaoliu.hrm.doc.CourseDoc;
import cn.xiaoliu.hrm.query.CourseDocQuery;
import cn.xiaoliu.hrm.repository.CourseDocRepository;
import cn.xiaoliu.hrm.util.AjaxResult;
import cn.xiaoliu.hrm.util.PageList;
import cn.xiaoliu.hrm.vo.AggVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/search")
public class CourseDocController {

    @Autowired
    private CourseDocRepository docRepository;
    @Autowired
    private HighlightResultMapper highlightResultMapper;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    //上线
    @PostMapping("/courseOnline")
    @PreAuthorize("hasAuthority('search:courseOnline')")
    public AjaxResult courseOnline(@RequestBody CourseDoc doc){
        CourseDoc save = docRepository.save(doc);
        return AjaxResult.me();
    }
    //下线
    @GetMapping("/courseOffline/{id}")
    @PreAuthorize("hasAuthority('search:courseOffline')")
    public AjaxResult courseOffline(@PathVariable("id") Long id){
        docRepository.deleteById(id);
        return AjaxResult.me();
    }

    /**
     * 全文检索实现分页和排序
     * @param docQuery
     * @return
     */
    @PostMapping("/queryCourses")
    public  AjaxResult queryCourses(@RequestBody CourseDocQuery docQuery){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //聚合查询
        builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20));
        builder.addAggregation(AggregationBuilders.terms("couseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)).size(20));

        //查询关键字高亮显示
        //设置高亮显示
        HighlightBuilder.Field highField = new HighlightBuilder.Field("name").preTags("<font style='color:blue'><b>").postTags("</b></font>");
        builder.withHighlightFields(highField);  // 名字高亮


        //关键字高级查询和过滤
        String keyword = docQuery.getKeyword();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(keyword)){
            //匹配多个字段
            boolQuery.must(QueryBuilders.multiMatchQuery(keyword,"name","courseTypeName","gradeName"));
        }
        //通过价格的范围过滤一波
        //获取最小价格
        Float min = docQuery.getPriceMin();
        if (min!=null){
            //价格要大于等于最小价格
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(min));
        }
        //获取最大价格
        Float max = docQuery.getPriceMax();
        if (max!=null){
            //价格要小于等于最大价格
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(max));
        }
        //高级查询匹配tenantName
        String tenantName = docQuery.getTenantName();
        if (!StringUtils.isEmpty(tenantName)){
            boolQuery.filter(QueryBuilders.termsQuery("tenantName",tenantName));
        }
        //高级查询匹配courseTypeName
        String courseTypeName = docQuery.getCourseTypeName();
        if (!StringUtils.isEmpty(courseTypeName)){
            boolQuery.filter(QueryBuilders.termsQuery("courseTypeName",courseTypeName));
        }

        builder.withQuery(boolQuery);


        //排序  根据字段排序
        String field = docQuery.getSortField();
        //判断里面有没有值，如果有就直接返回，没有就默认一个值
        field = StringUtils.isEmpty(field)?"price":field;

        //三目运算，如果前端返回的字段是desc，就用desc，如果不是就用asc
        SortOrder sortOrder = SortOrder.DESC.toString().equalsIgnoreCase(docQuery.getSortType())?SortOrder.DESC:SortOrder.ASC;

        builder.withSort(new FieldSortBuilder(field).order(sortOrder));


        //分页查询
        NativeSearchQueryBuilder queryBuilder = builder.withPageable(PageRequest.of(docQuery.getPage()-1, docQuery.getRows()));
        //调用CourseDocRepository进行查询
        //Repository不支持高亮
        //Page<CourseDoc> docPage = docRepository.search(builder.build());

        AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(builder.build(), CourseDoc.class, highlightResultMapper);
        //查询结果封装到pageList

        //封装聚合查询
        StringTerms tenantNameAgg = (StringTerms) page.getAggregation("tenantNameAgg");
        ArrayList<AggVo> tlist = new ArrayList<>();
        //获取buckets
        List<StringTerms.Bucket> tListBuckets = tenantNameAgg.getBuckets();
        tListBuckets.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setKey(bucket.getKeyAsString());
            aggVo.setCount(bucket.getDocCount());
            tlist.add(aggVo);
        });
        //封装聚合查询
        StringTerms cTypeNameAgg = (StringTerms) page.getAggregation("couseTypeAgg");
        ArrayList<AggVo> clist = new ArrayList<>();
        //获取buckets
        List<StringTerms.Bucket> cListBuckets = cTypeNameAgg.getBuckets();
        cListBuckets.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setKey(bucket.getKeyAsString());
            aggVo.setCount(bucket.getDocCount());
            clist.add(aggVo);
        });
        HashMap<String, ArrayList<AggVo>> map = new HashMap<>();
        map.put("tlist",tlist );
        map.put("clist",clist );
        PageList<CourseDoc> pageList = new PageList<>(page.getTotalElements(),page.getContent(),map);
        return AjaxResult.me().setResultObj(pageList);
    }
}
